﻿module game.transformmapper;

import gamelib.types;
import game.units;

struct TransformMapper
{
private:
    immutable Rect mViewport;
    immutable Point mViewCenter;
    immutable int mMaxRangeSq;
    pos_t mViewPos;
    rot_t mViewDir;
    transform_mat_t mViewMat;
public:
    this(in Rect viewport, in Point center) pure nothrow
    {
        mViewport = viewport;
        mViewCenter = center;
        import gamelib.math: max;
        mMaxRangeSq = (max((mViewCenter.x - mViewport.x),
                           (mViewport.x + mViewport.w - mViewCenter.x),
                           (mViewCenter.y - mViewport.y),
                           (mViewport.y + mViewport.h - mViewCenter.y)) * 2) ^^ 2;
        assert(mMaxRangeSq > 0);
    }

    @property void viewPos(in pos_t pos) pure nothrow { mViewPos = pos; }
    @property void viewDir(in rot_t dir) pure nothrow
    {
        mViewDir = dir;
        mViewMat = toRotMat(dir).transposed;
    }

    bool map(in pos_t srcPos,  in rot_t srcDir,
             out Point dstCenter, out double dstDir) const pure nothrow
    {
        auto relPos = srcPos - mViewPos;
        if(relPos.magnitude_squared > mMaxRangeSq)
        {
            return false;
        }
        auto relDir = mViewMat * srcDir;
        relPos = mViewMat * relPos;
        dstCenter = Point(mViewCenter.x - cast(int)relPos.y, mViewCenter.y - cast(int)relPos.x);
        dstDir = -toDegrees(relDir); //fuck
        return true;
    }

    Point map(in pos_t srcPos) const pure nothrow
    {
        auto relPos = srcPos - mViewPos;
        relPos = mViewMat * relPos;
        return Point(mViewCenter.x - cast(int)relPos.y, mViewCenter.y - cast(int)relPos.x);
    }
}

